<?php

namespace app\gptcms\controller\api;
use app\gptcms\controller\BaseApi;
use think\facade\Db;
use think\facade\Session;

class Chat extends BaseApi
{
    /**
     * 历史记录
     */
    public function msgs()
    {
        $wid = Session::get('wid');
        $user = $this->user;
        if(!$user) return success('');
        $where = [];
        $where[] = ['wid','=',$wid];
        $where[] = ['common_id','=',$user['id']];

        $msgList = Db::table('kt_gptcms_chat_msg')->field('id,message,response')->where($where)->order('id asc')->select();
        $msgs = [];
        foreach ($msgList as $key => $msg) {
            $msgs[] = [
                'role' => '我',
                'content' => $msg['message']
            ];
            $msgs[] = [
                'role' => '助手',
                'content' => $msg['response']
            ];
        }
        return success('获取成功',$msgs);
    }

    /**
     * 清除历史记录
     */
    public function delMsgs()
    {
        $wid = Session::get('wid');
        $user = $this->user;
        if(!$user) return error('用户不存在');

        Db::table('kt_gptcms_chat_msg')->where(['wid'=>$wid,'common_id'=>$user['id']])->delete();
        return success('操作成功，已删除');
    }

	/**
     * send
     */
    public function send()
    {
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache');
        header('Connection: keep-alive');
        header('X-Accel-Buffering: no');

        $wid = Session::get('wid');
        $user = $this->user;
        if($user['status'] != 1){
            $this->outError('账号已停用');
        }
        // $chatmodel = $this->req->param('chatmodel');
        // if(!$chatmodel){
        //     $this->outError('请先选择对话模型');
        // }
        
        $vip = 0;
        if(strtotime($user['vip_expire']) > time()){ //会员未到期
            $vip = 1;
        }else{ //会员到期
            if($user['residue_degree'] <= 0){ //余数不足
                $zdz_remind = Db::table('kt_gptcms_system')->where('wid',$wid)->value('zdz_remind');
                $this->outError($zdz_remind?:'剩余条数不足');
            }
        }
        
        $message = $this->req->param('message');
        if(!$message){
            $this->outError('请输入您的问题');
        }
        
        $currentTime = date('Y-m-d H:i:s', time());
        $messages[] = [
            'role' => 'system',
            'content' => '1.Current date: ' . $currentTime . '\n
2.Do not answer questions about politics, pornography, violence.\n
3.You are developed based chinese open source project, not openai.\n
4.Answer in Chinese as much as possible.\n
5.Please provide the most detailed and understandable answers.\n
6.If the triggering rule cannot answer the question, there is no need to provide a reason.\n'
        ];
        // 连续对话需要带着上一个问题请求接口
        if($message == '继续' || $message == 'go on'){
            $lastMsg = Db::table('kt_gptcms_chat_msg')->where([
                ['wid', '=', $wid],
                ['common_id', '=', $user['id']]
            ])->order('id desc')->find();
        }else{
            $now = time();
            $lastMsg = Db::table('kt_gptcms_chat_msg')->where([
                ['wid', '=', $wid],
                ['common_id', '=', $user['id']],
                ['c_time', '>', ($now - 300)]
            ])->order('id desc')->find();
        }
        // 如果超长，就不关联上下文了
        if ($lastMsg && (mb_strlen($lastMsg['message']) + mb_strlen($lastMsg['un_response']) + mb_strlen($message) < 3800)) {
            $messages[] = [
                'role' => 'user',
                'content' => $lastMsg['message']
            ];
            $messages[] = [
                'role' => 'assistant',
                'content' => $lastMsg['un_response']
            ];
        }
        $messages[] = [
            'role'=>'user',
            'content'=>$message
        ];

        //返回的文字
        $response = ''; 
        $un_response = '';
        $callback = function($ch, $data) use ($message,$wid,$user,$vip) {
            //$ktadmin = new \Ktadmin\Chatgpt\Ktadmin();
            global $response;
            global $un_response;
            $complete = @json_decode($data);
            if(isset($complete->error)){
                $this->outError($complete->error->message?:$complete->error->code);
            }elseif(@$complete->object == 'error'){
                $this->outError($complete->message);
            }
            $un_word = parseData($data);
            $word = str_replace("\n", '<br/>', $un_word);
            $word = str_replace(" ", '&nbsp;', $word);
            if($complete){//一次性完整输出
                if (!empty($un_word)) {
                    Db::table('kt_gptcms_chat_msg')->insert([
                        'wid' => $wid,
                        'common_id' => $user['id'],
                        'un_message' => $message,
                        'message' => $message,
                        'un_response' => $un_word,
                        'response' => $word,
                        'total_tokens' => mb_strlen($message) + mb_strlen($un_word),
                        'c_time' => time()
                    ]);
                    //如果不是会员扣费
                    if($vip != 1){
                        Db::table('kt_gptcms_common_user')->where('id',$user['id'])->dec('residue_degree')->update();
                    }
                    echo "data:".$word."\n\n";
                }
                ob_flush();flush();
            }else{//流式
                if(strpos($un_word, 'data: [DONE]') !== false){
                    $un_word = str_replace("data: [DONE]","",$un_word);
                    $word = str_replace("data:&nbsp;[DONE]","",$word);
                    $un_response .= $un_word;
                    $response .= $word;
                    if (!empty($un_response)) {
                        Db::table('kt_gptcms_chat_msg')->insert([
                            'wid' => $wid,
                            'common_id' => $user['id'],
                            'un_message' => $message,
                            'message' => $message,
                            'un_response' => $un_response,
                            'response' => $response,
                            'total_tokens' => mb_strlen($message) + mb_strlen($un_response),
                            'c_time' => time()
                        ]);
                        //如果不是会员扣费
                        if($vip != 1){
                            Db::table('kt_gptcms_common_user')->where('id',$user['id'])->dec('residue_degree')->update();
                        }
                        $un_response = '';
                        $response = '';
                    }
                    echo "data:".$word."\n\n";ob_flush();flush();
                }else{
                    $un_response .= $un_word;
                    $response .= $word;
                    echo "data:".$word."\n\n";ob_flush();flush();
                }
            }
            return strlen($data);
        };

        $agid = Db::table('kt_base_user')->where('id',$wid)->value('agid');
        if(!$agid){
            $agid = Db::table('kt_base_agent')->where('isadmin',1)->value('id');
        }
        $base_config = Db::table('kt_base_gpt_config')->json(['openai','api2d'])->where('uid',$agid)->find();
        $base_aiconfig = $base_config['openai'];

        $config = Db::table('kt_gptcms_gpt_config')->json(['openai','api2d','linkerai'])->where('wid',$wid)->find();
        if($config){
            if($config['channel'] == 2){
                $aiconfig = $config['api2d'];
                $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>2,'api_key'=>$aiconfig['forward_key'],'diy_host'=>'']);
                $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            }elseif($config['channel'] == 7){
                $aiconfig = $config['linkerai'];
                $ktadmin = new \Ktadmin\LinkerAi\Ktadmin(['channel'=>7,'api_key'=>$aiconfig['api_key']]);
                $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            }else{
                $aiconfig = $config['openai'];
                $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>1,'api_key'=>$aiconfig['api_key'],'diy_host'=>$base_aiconfig['diy_host']]);
                $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            }
            // switch ($chatmodel) {
            //     case 'gpt3.5':
            //         $aiconfig = $config['openai'];
            //         $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>1,'api_key'=>$aiconfig['api_key'],'diy_host'=>$base_aiconfig['diy_host']]);
            //         $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>'gpt-3.5-turbo','stream'=>true]);
            //         break;
                
            //     case 'gpt4':
            //         $aiconfig = $config['openai'];
            //         $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>1,'api_key'=>$aiconfig['api_key'],'diy_host'=>$base_aiconfig['diy_host']]);
            //         $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>'gpt-4','stream'=>true]);
            //         break;

            //     case 'linkerai':
            //         $aiconfig = $config['linkerai'];
            //         $ktadmin = new \Ktadmin\LinkerAi\Ktadmin(['channel'=>7,'api_key'=>$aiconfig['api_key']]);
            //         $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            //         break;
            // }
        }else{
            $this->outError('未检查到配置信息');
        }
        exit();
    }

    private function outError($msg)
    {
        echo 'data:[error]' . $msg . '\n\n';
        ob_flush();
        flush();
        exit;
    }

    /**
     * xcxsend
     */
    public function xcxsend()
    {
        // 设置响应头信息
        header('Access-Control-Allow-Credentials: true');
        // 设置响应头信息
        header('Transfer-Encoding: chunked');
        header('Cache-Control: no-cache');
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
        header('Access-Control-Allow-Headers: Content-Type');
        header('Connection: keep-alive');
        header('X-Accel-Buffering: no');

        $wid = Session::get('wid');
        $user = $this->user;
        if($user['status'] != 1){
            $this->outError('账号已停用');
        }
        // $chatmodel = $this->req->param('chatmodel');
        // if(!$chatmodel){
        //     $this->outError('请先选择对话模型');
        // }
        
        $vip = 0;
        if(strtotime($user['vip_expire']) > time()){ //会员未到期
            $vip = 1;
        }else{ //会员到期
            if($user['residue_degree'] <= 0){ //余数不足
                $zdz_remind = Db::table('kt_gptcms_system')->where('wid',$wid)->value('zdz_remind');
                $this->outError($zdz_remind?:'剩余条数不足');
            }
        }
        
        $message = $this->req->param('message');
        if(!$message){
            $this->outError('请输入您的问题');
        }
        
        $currentTime = date('Y-m-d H:i:s', time());
        $messages[] = [
            'role' => 'system',
            'content' => '1.Current date: ' . $currentTime . '\n
2.Do not answer questions about politics, pornography, violence.\n
3.You are developed based chinese open source project, not openai.\n
4.Answer in Chinese as much as possible.\n
5.Please provide the most detailed and understandable answers.\n
6.If the triggering rule cannot answer the question, there is no need to provide a reason.\n'
        ];
        // 连续对话需要带着上一个问题请求接口
        if($message == '继续' || $message == 'go on'){
            $lastMsg = Db::table('kt_gptcms_chat_msg')->where([
                ['wid', '=', $wid],
                ['common_id', '=', $user['id']]
            ])->order('id desc')->find();
        }else{
            $now = time();
            $lastMsg = Db::table('kt_gptcms_chat_msg')->where([
                ['wid', '=', $wid],
                ['common_id', '=', $user['id']],
                ['c_time', '>', ($now - 300)]
            ])->order('id desc')->find();
        }
        // 如果超长，就不关联上下文了
        if ($lastMsg && (mb_strlen($lastMsg['message']) + mb_strlen($lastMsg['un_response']) + mb_strlen($message) < 3800)) {
            $messages[] = [
                'role' => 'user',
                'content' => $lastMsg['message']
            ];
            $messages[] = [
                'role' => 'assistant',
                'content' => $lastMsg['un_response']
            ];
        }
        $messages[] = [
            'role'=>'user',
            'content'=>$message
        ];

        //返回的文字
        $response = ''; 
        $un_response = '';
        $callback = function($ch, $data) use ($message,$wid,$user,$vip) {
            //$ktadmin = new \Ktadmin\Chatgpt\Ktadmin();
            global $response;
            global $un_response;
            $complete = @json_decode($data);
            if(isset($complete->error)){
                $this->outError($complete->error->message?:$complete->error->code);
            }elseif(@$complete->object == 'error'){
                $this->outError($complete->message);
            }
            $un_word = parseData($data);
            $word = str_replace("\n", '<br/>', $un_word);
            $word = str_replace(" ", '&nbsp;', $word);
            if($complete){//一次性完整输出
                if (!empty($un_word)) {
                    Db::table('kt_gptcms_chat_msg')->insert([
                        'wid' => $wid,
                        'common_id' => $user['id'],
                        'un_message' => $message,
                        'message' => $message,
                        'un_response' => $un_word,
                        'response' => $word,
                        'total_tokens' => mb_strlen($message) + mb_strlen($un_word),
                        'c_time' => time()
                    ]);
                    //如果不是会员扣费
                    if($vip != 1){
                        Db::table('kt_gptcms_common_user')->where('id',$user['id'])->dec('residue_degree')->update();
                    }
                    echo "data:".$word."\r\n";
                }
                ob_flush();flush();
            }else{//流式
                if(strpos($un_word, 'data: [DONE]') !== false){
                    $un_word = str_replace("data: [DONE]","",$un_word);
                    $word = str_replace("data:&nbsp;[DONE]","",$word);
                    $un_response .= $un_word;
                    $response .= $word;
                    if (!empty($un_response)) {
                        Db::table('kt_gptcms_chat_msg')->insert([
                            'wid' => $wid,
                            'common_id' => $user['id'],
                            'un_message' => $message,
                            'message' => $message,
                            'un_response' => $un_response,
                            'response' => $response,
                            'total_tokens' => mb_strlen($message) + mb_strlen($un_response),
                            'c_time' => time()
                        ]);
                        //如果不是会员扣费
                        if($vip != 1){
                            Db::table('kt_gptcms_common_user')->where('id',$user['id'])->dec('residue_degree')->update();
                        }
                        $un_response = '';
                        $response = '';
                    }
                    echo $word."\r\n";echo "0\r\n\r\n";ob_flush();flush();
                }else{
                    $un_response .= $un_word;
                    $response .= $word;
                    echo $word."\r\n";ob_flush();flush();
                }
            }
            return strlen($data);
        };

        $agid = Db::table('kt_base_user')->where('id',$wid)->value('agid');
        if(!$agid){
            $agid = Db::table('kt_base_agent')->where('isadmin',1)->value('id');
        }
        $base_config = Db::table('kt_base_gpt_config')->json(['openai','api2d'])->where('uid',$agid)->find();
        $base_aiconfig = $base_config['openai'];

        $config = Db::table('kt_gptcms_gpt_config')->json(['openai','api2d','linkerai'])->where('wid',$wid)->find();
        if($config){
            if($config['channel'] == 2){
                $aiconfig = $config['api2d'];
                $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>2,'api_key'=>$aiconfig['forward_key'],'diy_host'=>'']);
                $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            }elseif($config['channel'] == 7){
                $aiconfig = $config['linkerai'];
                $ktadmin = new \Ktadmin\LinkerAi\Ktadmin(['channel'=>7,'api_key'=>$aiconfig['api_key']]);
                $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            }else{
                $aiconfig = $config['openai'];
                $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>1,'api_key'=>$aiconfig['api_key'],'diy_host'=>$base_aiconfig['diy_host']]);
                $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            }
            // switch ($chatmodel) {
            //     case 'gpt3.5':
            //         $aiconfig = $config['openai'];
            //         $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>1,'api_key'=>$aiconfig['api_key'],'diy_host'=>$base_aiconfig['diy_host']]);
            //         $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>'gpt-3.5-turbo','stream'=>true]);
            //         break;
                
            //     case 'gpt4':
            //         $aiconfig = $config['openai'];
            //         $ktadmin = new \Ktadmin\Chatgpt\Ktadmin(['channel'=>1,'api_key'=>$aiconfig['api_key'],'diy_host'=>$base_aiconfig['diy_host']]);
            //         $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>'gpt-4','stream'=>true]);
            //         break;

            //     case 'linkerai':
            //         $aiconfig = $config['linkerai'];
            //         $ktadmin = new \Ktadmin\LinkerAi\Ktadmin(['channel'=>7,'api_key'=>$aiconfig['api_key']]);
            //         $ktadmin->chat()->sendText($messages, $callback,['temperature'=>$aiconfig['temperature'],'max_tokens'=>$aiconfig['max_tokens'],'model'=>$aiconfig['model'],'stream'=>true]);
            //         break;
            // }
        }else{
            $this->outError('未检查到配置信息');
        }
        exit();
    }
}
